1 Scraping the NSF News Article for Featured Datasets

On August 28, 2025, the National Science Foundation announced two major advancements in America’s AI infrastructure:

  1. the launch of the Integrated Data Systems and Services (NSF IDSS) program to build out national-scale data systems, and
  2. the selection of 10 datasets for integration into the National Artificial Intelligence Research Resource (NAIRR) Pilot

The datasets were selected through a competitive process led by NSF in partnership with an interagency working group of 12 federal agencies, inviting submissions supporting AI skill development across various learning environments to help grow the nation’s AI-literate workforce.

Below, we scrape the news article to extract the names of the 10 datasets and their associated data.

nsf_news_page = rvest::read_html(
  "https://www.nsf.gov/news/nsf-expanding-national-ai-infrastructure-new-data-systems"
  )

datasets_tbl = tibble::tibble(
  lead_university = rvest::html_elements(
    nsf_news_page , 
    xpath = "//*[@id=\"block-nsf-theme-content\"]/article/div/div[1]/div/div/main/div[4]/div/ul[2]/li/text()"
    ) |> 
    rvest::html_text2() |> 
    stringr::str_remove_all("\\(|\\)"),
  name = rvest::html_elements(nsf_news_page , "ul:nth-child(14) > li > a") |> 
    rvest::html_text2(),
  primary_url = rvest::html_elements(nsf_news_page , "ul:nth-child(14) > li > a") |> 
    rvest::html_attr("href"),
  secondary_url = c(
  "https://umfieldrobotics.github.io/ai4shipwrecks/overview/",
  "https://turbulence.idies.jhu.edu/database",
  "https://registry.opendata.aws/cellpainting-gallery/",
  "https://database.fathomnet.org/fathomnet/#/about",
  "https://github.com/SunLab-GMU/PatchDB",
  "https://github.com/maryhzd/Phase-field",
  "https://www.cs.purdue.edu/news/articles/2025/purdue-researchers-build-securechain-to-strengthen-software-supply-chain-security.html",
  "https://www.synapse.org/Synapse:syn26133770",
  "https://www.library.ucsf.edu/archives/industry-documents/",
  "https://portal.opentopography.org/dataCatalog"
)
)

DT::datatable(
  datasets_tbl,
  extensions = c('Buttons'),
  options = list(
    pageLength = 10, autoWidth = TRUE, scrollX = TRUE,
    dom = 'Bfrtip',
    buttons = c('copy', 'csv', 'excel', 'pdf', 'print')
    )
  )

2 Curated Metadata about the Datasets

2.1 Reading the Curated Metadata

We curated information from these datasets into a nsf_idss_curated_dataset_summaries.csv, which we read here.

supp_df = readr::read_csv("../data/nsf_idss_curated_dataset_summaries.csv", show_col_types = FALSE)

DT::datatable(
  supp_df,
  extensions = c('Buttons'),
  options = list(
    pageLength = 10, autoWidth = TRUE, scrollX = TRUE,
    dom = 'Bfrtip',
    buttons = c('copy', 'csv', 'excel', 'pdf', 'print')
    )
  )

2.2 Merging the Curated Metadata with the Scraped Data

full_df = dplyr::bind_cols(
  datasets_tbl, 
  supp_df |> dplyr::select(-c(primary_url, secondary_url))
  ) |> 
  dplyr::select(
    lead_university, domain_discipline, name, description_short, data_size,
    n_records_images_samples, temporal_spatial_coverage, 
    primary_url, secondary_url
    )

readr::write_csv(full_df, "../data/nsf_idss_full_dataset_summaries.csv")

DT::datatable(
  full_df,
  extensions = c('Buttons'),
  options = list(
    pageLength = 10, autoWidth = TRUE, scrollX = TRUE,
    dom = 'Bfrtip',
    buttons = c('copy', 'csv', 'excel', 'pdf', 'print')
    )
  )

3 But, NSF Focus Areas

The NSF Focus Areas page lists the current focus areas and subareas, which we scrape below. We will use these to classify the datasets into focus areas. We use the classify_datasets function defined in utils.R, which leverages the OpenAI API to perform the classification.

source("utils.R")

"https://www.nsf.gov/focus-areas" |>  
  rvest::read_html() |> 
  rvest::html_elements("div > div > h2 > a") |> 
  rvest::html_text2() -> focus_area_nodes

focus_areas_tbl = tibble::tibble(
  focus_area = focus_area_nodes,
  source = "https://www.nsf.gov/focus-areas"
)

"https://www.nsf.gov/focus-areas" |>  
  rvest::read_html() |> 
  rvest::html_elements("li > h4 > a") |> 
  rvest::html_text2() -> technology_sub_nodes

technology_subareas_tbl = tibble::tibble(
  focus_area = "Technology",
  subarea    = technology_sub_nodes,
  source     = "https://www.nsf.gov/focus-areas"
)

nsf_focus_tbl = dplyr::left_join(
  focus_areas_tbl, technology_subareas_tbl, by = c("focus_area", "source")
)

mapping_tbl = classify_datasets(full_df, nsf_focus_tbl) |> 
  dplyr::select(-dataset_name)

readr::write_csv(mapping_tbl, "../data/nsf_dataset_to_focus_area_mapping.csv")

DT::datatable(mapping_tbl)

4 Plots

We create three plots to understand how the datasets map to NSF focus areas and subareas, especially within Technology. The plots utilize the chosen_focus_area column from the mapping results, which was generated using the OpenAI API via the classify_datasets function in utils.R.

source("utils.R")
focus_counts = mapping_tbl |>
  dplyr::count(chosen_focus_area, name = "n") |>
  dplyr::arrange(n) |>
  dplyr::mutate(
    fill_col = dplyr::if_else(stringr::str_detect(chosen_focus_area, "Technology"), miamired, "#b0b0b0"),
    chosen_focus_area = forcats::fct_reorder(chosen_focus_area, n)
  )

# Plot 1: Overview of focus areas
p1 = ggplot2::ggplot(focus_counts, ggplot2::aes(x = n, y = chosen_focus_area)) +
  ggplot2::geom_col(ggplot2::aes(fill = fill_col), width = 0.7) +
  ggplot2::scale_fill_identity() +
  ggplot2::geom_text(ggplot2::aes(label = n), hjust = -0.2, size = 3.8) +
  ggplot2::labs(
    title = "Where the datasets map across NSF focus areas",
    subtitle = "Vocabulary scraped from the official NSF <i>Our Focus Areas</i> page",
    x = "Number of datasets", y = NULL,
    caption = "Source: nsf.gov/focus-areas (scraped); ; MU NSF IDSS Team"
  ) +
  ggplot2::coord_cartesian(xlim = c(0, max(focus_counts$n) * 1.15))

ggplot2::ggsave("../figs/fig01_focus_areas_overview.png", p1, width = 12, height = 5, dpi = 300)

# Plot 2: Technology subareas, highlighting Advanced Manufacturing gap
tech_levels = nsf_focus_tbl$subarea |>
  unique() |>
  stats::na.omit() |>
  as.character() |>
  sort()

mapping_tbl_with_tech = mapping_tbl |>
  dplyr::mutate(
    chosen_technology_subarea = dplyr::case_when(
      stringr::str_starts(tidyr::replace_na(chosen_focus_area, ""), "Technology > ") ~
        stringr::str_remove(chosen_focus_area, "^Technology > "),
      TRUE ~ "Non-Technology"
    )
  )

tech_counts_raw = mapping_tbl_with_tech |> 
  dplyr::count(chosen_technology_subarea, name = "n")

tech_counts = tibble::tibble(subarea = tech_levels) |>
  dplyr::left_join(
    tech_counts_raw |> dplyr::rename(subarea = chosen_technology_subarea),
    by = "subarea"
  ) |>
  dplyr::mutate(
    n = tidyr::replace_na(n, 0L),
    subarea = forcats::fct_relevel(subarea, "Advanced Manufacturing", after = 0),
    col = dplyr::if_else(subarea == "Advanced Manufacturing", miamired, "#b0b0b0")
  ) |>
  dplyr::arrange(subarea)

p2 = ggplot2::ggplot(tech_counts, ggplot2::aes(y = subarea, x = n)) +
  ggplot2::geom_segment(ggplot2::aes(yend = subarea, x = 0, xend = n), color = "#b0b0b0") +
  ggplot2::geom_point(ggplot2::aes(color = col), size = 3.2) +
  ggplot2::scale_color_identity() +
  ggplot2::geom_text(ggplot2::aes(label = n), hjust = -0.4, size = 3.4) +
  ggplot2::labs(
    title = "Technology subareas represented by the datasets",
    subtitle = "All NSF technology subareas shown to reveal gaps; <b style='color:#c3142d;'>Advanced Manufacturing</b> highlighted",
    x = "Number of datasets", y = NULL,
    caption = "Source: nsf.gov/focus-areas (scraped); MU NSF IDSS Team"
  ) +
  ggplot2::coord_cartesian(xlim = c(0, max(tech_counts$n) * 1.3 + 0.5))

# Optional: explicit gap callout if zero
am_n = tech_counts$n[tech_counts$subarea == "Advanced Manufacturing"]
if (length(am_n) == 1 && am_n == 0) {
  p2 = p2 +
    ggplot2::annotate("label",
      x = max(tech_counts$n) * 0.6, y = which(levels(tech_counts$subarea) == "Advanced Manufacturing"),
      label = "Gap: No datasets mapped to Advanced Manufacturing",
      color = "white", fill = miamired, label.size = NA, size = 3.5
    )
}
ggplot2::ggsave("../figs/fig02_technology_subareas_gap.png", p2, width = 12, height = 5, dpi = 300)

# Plot 3: Flow (alluvial) from Domain -> Focus -> Subarea
flow_df = mapping_tbl_with_tech |>
  dplyr::mutate(
    sub3 = dplyr::if_else(
      is.na(chosen_technology_subarea) | chosen_technology_subarea == "",
      "Non-Technology",
      chosen_technology_subarea
    )
  ) |>
  dplyr::count(domain_discipline, chosen_focus_area, sub3, name = "n") |>
  dplyr::mutate(
    fill_grp = dplyr::if_else(sub3 == "Advcanced Manufacturing", "am", "other")
  )

p3 = ggplot2::ggplot(
  flow_df,
  ggplot2::aes(axis1 = domain_discipline, axis2 = chosen_focus_area, axis3 = sub3, y = n)
) +
  ggalluvial::geom_alluvium(ggplot2::aes(fill = fill_grp), width = 0.2, alpha = 0.7) +
  ggalluvial::geom_stratum(width = 0.25, fill = "#b0b0b0", color = "white") +
  ggplot2::geom_text(
        ggplot2::aes(
      label = ggplot2::after_stat(stratum)
      ),
    stat = ggalluvial::StatStratum, 
    size = 2.55, 
    fontface = "bold",
    color = 'black'
  ) +
  ggplot2::scale_fill_manual(
    values = c(am = miamired, other = 'lightgray'),
    guide = "none"
  ) +
  ggplot2::labs(
    title = "How domains map to NSF focus areas and technology subareas",
    subtitle = "Widths indicate dataset counts; <b style='color:#c3142d;'>Advanced Manufacturing</b> highlighted when present",
    x = NULL, y = "Datasets",
    caption = "Source: nsf.gov/focus-areas (scraped); MU NSF IDSS Team"
  ) +
  ggplot2::theme(
    axis.ticks.x = ggplot2::element_blank(),
    axis.text.x  = ggplot2::element_blank(),
    axis.ticks.y = ggplot2::element_blank(),
    axis.text.y  = ggplot2::element_blank()
  )

ggplot2::ggsave("../figs/fig03_domain_to_focus_flow.png", p3, width = 12, height = 5, dpi = 300)

# Animation of the three plots
image_files = list.files("../figs/", pattern = "^fig0.*\\.png$", full.names = TRUE)
image_list = magick::image_read(image_files)
animation = magick::image_animate(image_list, delay = 750, loop = 0)

magick::image_write(animation, "../figs/nsf_idss_focus_areas_animation.gif")

animation

LS0tDQp0aXRsZTogIlVuZGVyc3RhbmRpbmcgUHJldmlvdXNseSBGdW5kZWQgUHJvamVjdHMiDQphdXRob3I6ICJNVSBOU0YgSURTUyBQcm9wb3NhbCBUZWFtIg0KZGF0ZTogImByIFN5cy5EYXRlKClgIg0Kb3V0cHV0OiANCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZGVwdGg6IDINCiAgICB0b2NfZmxvYXQ6IHRydWUNCiAgICB0aGVtZTogc2ltcGxleA0KICAgIGhpZ2hsaWdodDogdGFuZ28NCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUNCiAgICBkZl9wcmludDogcGFnZWQNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICAgc2VsZl9jb250YWluZWQ6IHRydWUNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgY2FjaGUgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UpDQpgYGANCg0KIyBTY3JhcGluZyB0aGUgTlNGIE5ld3MgQXJ0aWNsZSBmb3IgRmVhdHVyZWQgRGF0YXNldHMNCg0KT24gQXVndXN0IDI4LCAyMDI1LCBbdGhlIE5hdGlvbmFsIFNjaWVuY2UgRm91bmRhdGlvbiBhbm5vdW5jZWQgdHdvIG1ham9yIGFkdmFuY2VtZW50cyBpbiBBbWVyaWNhJ3MgQUkgaW5mcmFzdHJ1Y3R1cmVdKGh0dHBzOi8vd3d3Lm5zZi5nb3YvbmV3cy9uc2YtZXhwYW5kaW5nLW5hdGlvbmFsLWFpLWluZnJhc3RydWN0dXJlLW5ldy1kYXRhLXN5c3RlbXMpOiAgIA0KDQoxLiB0aGUgbGF1bmNoIG9mIHRoZSBJbnRlZ3JhdGVkIERhdGEgU3lzdGVtcyBhbmQgU2VydmljZXMgKE5TRiBJRFNTKSBwcm9ncmFtIHRvIGJ1aWxkIG91dCBuYXRpb25hbC1zY2FsZSBkYXRhIHN5c3RlbXMsIGFuZCAgDQoyLiB0aGUgc2VsZWN0aW9uIG9mIDEwIGRhdGFzZXRzIGZvciBpbnRlZ3JhdGlvbiBpbnRvIHRoZSBbTmF0aW9uYWwgQXJ0aWZpY2lhbCBJbnRlbGxpZ2VuY2UgUmVzZWFyY2ggUmVzb3VyY2UgKE5BSVJSKSBQaWxvdF0oaHR0cHM6Ly9uYWlycnBpbG90Lm9yZy8pIA0KDQo+IFRoZSBkYXRhc2V0cyB3ZXJlIHNlbGVjdGVkIHRocm91Z2ggYSBjb21wZXRpdGl2ZSBwcm9jZXNzIGxlZCBieSBOU0YgaW4gcGFydG5lcnNoaXAgd2l0aCBhbiBpbnRlcmFnZW5jeSB3b3JraW5nIGdyb3VwIG9mIDEyIGZlZGVyYWwgYWdlbmNpZXMsIGludml0aW5nIHN1Ym1pc3Npb25zIHN1cHBvcnRpbmcgQUkgc2tpbGwgZGV2ZWxvcG1lbnQgYWNyb3NzIHZhcmlvdXMgbGVhcm5pbmcgZW52aXJvbm1lbnRzIHRvIGhlbHAgZ3JvdyB0aGUgbmF0aW9uJ3MgQUktbGl0ZXJhdGUgd29ya2ZvcmNlLg0KDQpCZWxvdywgd2Ugc2NyYXBlIHRoZSBuZXdzIGFydGljbGUgdG8gZXh0cmFjdCB0aGUgbmFtZXMgb2YgdGhlIDEwIGRhdGFzZXRzIGFuZCB0aGVpciBhc3NvY2lhdGVkIGRhdGEuDQoNCmBgYHtyIHNjcmFwZXJ9DQpuc2ZfbmV3c19wYWdlID0gcnZlc3Q6OnJlYWRfaHRtbCgNCiAgImh0dHBzOi8vd3d3Lm5zZi5nb3YvbmV3cy9uc2YtZXhwYW5kaW5nLW5hdGlvbmFsLWFpLWluZnJhc3RydWN0dXJlLW5ldy1kYXRhLXN5c3RlbXMiDQogICkNCg0KZGF0YXNldHNfdGJsID0gdGliYmxlOjp0aWJibGUoDQogIGxlYWRfdW5pdmVyc2l0eSA9IHJ2ZXN0OjpodG1sX2VsZW1lbnRzKA0KICAgIG5zZl9uZXdzX3BhZ2UgLCANCiAgICB4cGF0aCA9ICIvLypbQGlkPVwiYmxvY2stbnNmLXRoZW1lLWNvbnRlbnRcIl0vYXJ0aWNsZS9kaXYvZGl2WzFdL2Rpdi9kaXYvbWFpbi9kaXZbNF0vZGl2L3VsWzJdL2xpL3RleHQoKSINCiAgICApIHw+IA0KICAgIHJ2ZXN0OjpodG1sX3RleHQyKCkgfD4gDQogICAgc3RyaW5ncjo6c3RyX3JlbW92ZV9hbGwoIlxcKHxcXCkiKSwNCiAgbmFtZSA9IHJ2ZXN0OjpodG1sX2VsZW1lbnRzKG5zZl9uZXdzX3BhZ2UgLCAidWw6bnRoLWNoaWxkKDE0KSA+IGxpID4gYSIpIHw+IA0KICAgIHJ2ZXN0OjpodG1sX3RleHQyKCksDQogIHByaW1hcnlfdXJsID0gcnZlc3Q6Omh0bWxfZWxlbWVudHMobnNmX25ld3NfcGFnZSAsICJ1bDpudGgtY2hpbGQoMTQpID4gbGkgPiBhIikgfD4gDQogICAgcnZlc3Q6Omh0bWxfYXR0cigiaHJlZiIpLA0KICBzZWNvbmRhcnlfdXJsID0gYygNCiAgImh0dHBzOi8vdW1maWVsZHJvYm90aWNzLmdpdGh1Yi5pby9haTRzaGlwd3JlY2tzL292ZXJ2aWV3LyIsDQogICJodHRwczovL3R1cmJ1bGVuY2UuaWRpZXMuamh1LmVkdS9kYXRhYmFzZSIsDQogICJodHRwczovL3JlZ2lzdHJ5Lm9wZW5kYXRhLmF3cy9jZWxscGFpbnRpbmctZ2FsbGVyeS8iLA0KICAiaHR0cHM6Ly9kYXRhYmFzZS5mYXRob21uZXQub3JnL2ZhdGhvbW5ldC8jL2Fib3V0IiwNCiAgImh0dHBzOi8vZ2l0aHViLmNvbS9TdW5MYWItR01VL1BhdGNoREIiLA0KICAiaHR0cHM6Ly9naXRodWIuY29tL21hcnloemQvUGhhc2UtZmllbGQiLA0KICAiaHR0cHM6Ly93d3cuY3MucHVyZHVlLmVkdS9uZXdzL2FydGljbGVzLzIwMjUvcHVyZHVlLXJlc2VhcmNoZXJzLWJ1aWxkLXNlY3VyZWNoYWluLXRvLXN0cmVuZ3RoZW4tc29mdHdhcmUtc3VwcGx5LWNoYWluLXNlY3VyaXR5Lmh0bWwiLA0KICAiaHR0cHM6Ly93d3cuc3luYXBzZS5vcmcvU3luYXBzZTpzeW4yNjEzMzc3MCIsDQogICJodHRwczovL3d3dy5saWJyYXJ5LnVjc2YuZWR1L2FyY2hpdmVzL2luZHVzdHJ5LWRvY3VtZW50cy8iLA0KICAiaHR0cHM6Ly9wb3J0YWwub3BlbnRvcG9ncmFwaHkub3JnL2RhdGFDYXRhbG9nIg0KKQ0KKQ0KDQpEVDo6ZGF0YXRhYmxlKA0KICBkYXRhc2V0c190YmwsDQogIGV4dGVuc2lvbnMgPSBjKCdCdXR0b25zJyksDQogIG9wdGlvbnMgPSBsaXN0KA0KICAgIHBhZ2VMZW5ndGggPSAxMCwgYXV0b1dpZHRoID0gVFJVRSwgc2Nyb2xsWCA9IFRSVUUsDQogICAgZG9tID0gJ0JmcnRpcCcsDQogICAgYnV0dG9ucyA9IGMoJ2NvcHknLCAnY3N2JywgJ2V4Y2VsJywgJ3BkZicsICdwcmludCcpDQogICAgKQ0KICApDQpgYGANCg0KDQoNCiMgQ3VyYXRlZCBNZXRhZGF0YSBhYm91dCB0aGUgRGF0YXNldHMNCg0KIyMgUmVhZGluZyB0aGUgQ3VyYXRlZCBNZXRhZGF0YQ0KDQpXZSBjdXJhdGVkIGluZm9ybWF0aW9uIGZyb20gdGhlc2UgZGF0YXNldHMgaW50byBhIGBuc2ZfaWRzc19jdXJhdGVkX2RhdGFzZXRfc3VtbWFyaWVzLmNzdmAsIHdoaWNoIHdlIHJlYWQgaGVyZS4NCg0KYGBge3IgbWV0YWRhdGFfcmVhZGluZ30NCnN1cHBfZGYgPSByZWFkcjo6cmVhZF9jc3YoIi4uL2RhdGEvbnNmX2lkc3NfY3VyYXRlZF9kYXRhc2V0X3N1bW1hcmllcy5jc3YiLCBzaG93X2NvbF90eXBlcyA9IEZBTFNFKQ0KDQpEVDo6ZGF0YXRhYmxlKA0KICBzdXBwX2RmLA0KICBleHRlbnNpb25zID0gYygnQnV0dG9ucycpLA0KICBvcHRpb25zID0gbGlzdCgNCiAgICBwYWdlTGVuZ3RoID0gMTAsIGF1dG9XaWR0aCA9IFRSVUUsIHNjcm9sbFggPSBUUlVFLA0KICAgIGRvbSA9ICdCZnJ0aXAnLA0KICAgIGJ1dHRvbnMgPSBjKCdjb3B5JywgJ2NzdicsICdleGNlbCcsICdwZGYnLCAncHJpbnQnKQ0KICAgICkNCiAgKQ0KYGBgDQoNCiMjIE1lcmdpbmcgdGhlIEN1cmF0ZWQgTWV0YWRhdGEgd2l0aCB0aGUgU2NyYXBlZCBEYXRhDQoNCmBgYHtyIG1ldGFkYXRhX21lcmdpbmd9DQpmdWxsX2RmID0gZHBseXI6OmJpbmRfY29scygNCiAgZGF0YXNldHNfdGJsLCANCiAgc3VwcF9kZiB8PiBkcGx5cjo6c2VsZWN0KC1jKHByaW1hcnlfdXJsLCBzZWNvbmRhcnlfdXJsKSkNCiAgKSB8PiANCiAgZHBseXI6OnNlbGVjdCgNCiAgICBsZWFkX3VuaXZlcnNpdHksIGRvbWFpbl9kaXNjaXBsaW5lLCBuYW1lLCBkZXNjcmlwdGlvbl9zaG9ydCwgZGF0YV9zaXplLA0KICAgIG5fcmVjb3Jkc19pbWFnZXNfc2FtcGxlcywgdGVtcG9yYWxfc3BhdGlhbF9jb3ZlcmFnZSwgDQogICAgcHJpbWFyeV91cmwsIHNlY29uZGFyeV91cmwNCiAgICApDQoNCnJlYWRyOjp3cml0ZV9jc3YoZnVsbF9kZiwgIi4uL2RhdGEvbnNmX2lkc3NfZnVsbF9kYXRhc2V0X3N1bW1hcmllcy5jc3YiKQ0KDQpEVDo6ZGF0YXRhYmxlKA0KICBmdWxsX2RmLA0KICBleHRlbnNpb25zID0gYygnQnV0dG9ucycpLA0KICBvcHRpb25zID0gbGlzdCgNCiAgICBwYWdlTGVuZ3RoID0gMTAsIGF1dG9XaWR0aCA9IFRSVUUsIHNjcm9sbFggPSBUUlVFLA0KICAgIGRvbSA9ICdCZnJ0aXAnLA0KICAgIGJ1dHRvbnMgPSBjKCdjb3B5JywgJ2NzdicsICdleGNlbCcsICdwZGYnLCAncHJpbnQnKQ0KICAgICkNCiAgKQ0KDQpgYGANCg0KDQojIEJ1dCwgTlNGIEZvY3VzIEFyZWFzIA0KDQpUaGUgW05TRiBGb2N1cyBBcmVhc10oaHR0cHM6Ly93d3cubnNmLmdvdi9mb2N1cy1hcmVhcykgcGFnZSBsaXN0cyB0aGUgY3VycmVudCBmb2N1cyBhcmVhcyBhbmQgc3ViYXJlYXMsIHdoaWNoIHdlIHNjcmFwZSBiZWxvdy4gV2Ugd2lsbCB1c2UgdGhlc2UgdG8gY2xhc3NpZnkgdGhlIGRhdGFzZXRzIGludG8gZm9jdXMgYXJlYXMuIFdlIHVzZSB0aGUgYGNsYXNzaWZ5X2RhdGFzZXRzYCBmdW5jdGlvbiBkZWZpbmVkIGluIGB1dGlscy5SYCwgd2hpY2ggbGV2ZXJhZ2VzIHRoZSBgT3BlbkFJIEFQSWAgdG8gcGVyZm9ybSB0aGUgY2xhc3NpZmljYXRpb24uIA0KDQoNCmBgYHtyIG5zZl9mb2N1cywgY2FjaGU9VFJVRX0NCnNvdXJjZSgidXRpbHMuUiIpDQoNCiJodHRwczovL3d3dy5uc2YuZ292L2ZvY3VzLWFyZWFzIiB8PiAgDQogIHJ2ZXN0OjpyZWFkX2h0bWwoKSB8PiANCiAgcnZlc3Q6Omh0bWxfZWxlbWVudHMoImRpdiA+IGRpdiA+IGgyID4gYSIpIHw+IA0KICBydmVzdDo6aHRtbF90ZXh0MigpIC0+IGZvY3VzX2FyZWFfbm9kZXMNCg0KZm9jdXNfYXJlYXNfdGJsID0gdGliYmxlOjp0aWJibGUoDQogIGZvY3VzX2FyZWEgPSBmb2N1c19hcmVhX25vZGVzLA0KICBzb3VyY2UgPSAiaHR0cHM6Ly93d3cubnNmLmdvdi9mb2N1cy1hcmVhcyINCikNCg0KImh0dHBzOi8vd3d3Lm5zZi5nb3YvZm9jdXMtYXJlYXMiIHw+ICANCiAgcnZlc3Q6OnJlYWRfaHRtbCgpIHw+IA0KICBydmVzdDo6aHRtbF9lbGVtZW50cygibGkgPiBoNCA+IGEiKSB8PiANCiAgcnZlc3Q6Omh0bWxfdGV4dDIoKSAtPiB0ZWNobm9sb2d5X3N1Yl9ub2Rlcw0KDQp0ZWNobm9sb2d5X3N1YmFyZWFzX3RibCA9IHRpYmJsZTo6dGliYmxlKA0KICBmb2N1c19hcmVhID0gIlRlY2hub2xvZ3kiLA0KICBzdWJhcmVhICAgID0gdGVjaG5vbG9neV9zdWJfbm9kZXMsDQogIHNvdXJjZSAgICAgPSAiaHR0cHM6Ly93d3cubnNmLmdvdi9mb2N1cy1hcmVhcyINCikNCg0KbnNmX2ZvY3VzX3RibCA9IGRwbHlyOjpsZWZ0X2pvaW4oDQogIGZvY3VzX2FyZWFzX3RibCwgdGVjaG5vbG9neV9zdWJhcmVhc190YmwsIGJ5ID0gYygiZm9jdXNfYXJlYSIsICJzb3VyY2UiKQ0KKQ0KDQptYXBwaW5nX3RibCA9IGNsYXNzaWZ5X2RhdGFzZXRzKGZ1bGxfZGYsIG5zZl9mb2N1c190YmwpIHw+IA0KICBkcGx5cjo6c2VsZWN0KC1kYXRhc2V0X25hbWUpDQoNCnJlYWRyOjp3cml0ZV9jc3YobWFwcGluZ190YmwsICIuLi9kYXRhL25zZl9kYXRhc2V0X3RvX2ZvY3VzX2FyZWFfbWFwcGluZy5jc3YiKQ0KDQpEVDo6ZGF0YXRhYmxlKG1hcHBpbmdfdGJsKQ0KYGBgDQoNCiMgUGxvdHMNCg0KV2UgY3JlYXRlIHRocmVlIHBsb3RzIHRvIHVuZGVyc3RhbmQgaG93IHRoZSBkYXRhc2V0cyBtYXAgdG8gTlNGIGZvY3VzIGFyZWFzIGFuZCBzdWJhcmVhcywgZXNwZWNpYWxseSB3aXRoaW4gVGVjaG5vbG9neS4gVGhlIHBsb3RzIHV0aWxpemUgdGhlIGBjaG9zZW5fZm9jdXNfYXJlYWAgY29sdW1uIGZyb20gdGhlIG1hcHBpbmcgcmVzdWx0cywgd2hpY2ggd2FzIGdlbmVyYXRlZCB1c2luZyB0aGUgYE9wZW5BSSBBUElgIHZpYSB0aGUgYGNsYXNzaWZ5X2RhdGFzZXRzYCBmdW5jdGlvbiBpbiBgdXRpbHMuUmAuDQoNCmBgYHtyIHBsb3RzfQ0Kc291cmNlKCJ1dGlscy5SIikNCmZvY3VzX2NvdW50cyA9IG1hcHBpbmdfdGJsIHw+DQogIGRwbHlyOjpjb3VudChjaG9zZW5fZm9jdXNfYXJlYSwgbmFtZSA9ICJuIikgfD4NCiAgZHBseXI6OmFycmFuZ2UobikgfD4NCiAgZHBseXI6Om11dGF0ZSgNCiAgICBmaWxsX2NvbCA9IGRwbHlyOjppZl9lbHNlKHN0cmluZ3I6OnN0cl9kZXRlY3QoY2hvc2VuX2ZvY3VzX2FyZWEsICJUZWNobm9sb2d5IiksIG1pYW1pcmVkLCAiI2IwYjBiMCIpLA0KICAgIGNob3Nlbl9mb2N1c19hcmVhID0gZm9yY2F0czo6ZmN0X3Jlb3JkZXIoY2hvc2VuX2ZvY3VzX2FyZWEsIG4pDQogICkNCg0KIyBQbG90IDE6IE92ZXJ2aWV3IG9mIGZvY3VzIGFyZWFzDQpwMSA9IGdncGxvdDI6OmdncGxvdChmb2N1c19jb3VudHMsIGdncGxvdDI6OmFlcyh4ID0gbiwgeSA9IGNob3Nlbl9mb2N1c19hcmVhKSkgKw0KICBnZ3Bsb3QyOjpnZW9tX2NvbChnZ3Bsb3QyOjphZXMoZmlsbCA9IGZpbGxfY29sKSwgd2lkdGggPSAwLjcpICsNCiAgZ2dwbG90Mjo6c2NhbGVfZmlsbF9pZGVudGl0eSgpICsNCiAgZ2dwbG90Mjo6Z2VvbV90ZXh0KGdncGxvdDI6OmFlcyhsYWJlbCA9IG4pLCBoanVzdCA9IC0wLjIsIHNpemUgPSAzLjgpICsNCiAgZ2dwbG90Mjo6bGFicygNCiAgICB0aXRsZSA9ICJXaGVyZSB0aGUgZGF0YXNldHMgbWFwIGFjcm9zcyBOU0YgZm9jdXMgYXJlYXMiLA0KICAgIHN1YnRpdGxlID0gIlZvY2FidWxhcnkgc2NyYXBlZCBmcm9tIHRoZSBvZmZpY2lhbCBOU0YgPGk+T3VyIEZvY3VzIEFyZWFzPC9pPiBwYWdlIiwNCiAgICB4ID0gIk51bWJlciBvZiBkYXRhc2V0cyIsIHkgPSBOVUxMLA0KICAgIGNhcHRpb24gPSAiU291cmNlOiBuc2YuZ292L2ZvY3VzLWFyZWFzIChzY3JhcGVkKTsgOyBNVSBOU0YgSURTUyBUZWFtIg0KICApICsNCiAgZ2dwbG90Mjo6Y29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDAsIG1heChmb2N1c19jb3VudHMkbikgKiAxLjE1KSkNCg0KZ2dwbG90Mjo6Z2dzYXZlKCIuLi9maWdzL2ZpZzAxX2ZvY3VzX2FyZWFzX292ZXJ2aWV3LnBuZyIsIHAxLCB3aWR0aCA9IDEyLCBoZWlnaHQgPSA1LCBkcGkgPSAzMDApDQoNCiMgUGxvdCAyOiBUZWNobm9sb2d5IHN1YmFyZWFzLCBoaWdobGlnaHRpbmcgQWR2YW5jZWQgTWFudWZhY3R1cmluZyBnYXANCnRlY2hfbGV2ZWxzID0gbnNmX2ZvY3VzX3RibCRzdWJhcmVhIHw+DQogIHVuaXF1ZSgpIHw+DQogIHN0YXRzOjpuYS5vbWl0KCkgfD4NCiAgYXMuY2hhcmFjdGVyKCkgfD4NCiAgc29ydCgpDQoNCm1hcHBpbmdfdGJsX3dpdGhfdGVjaCA9IG1hcHBpbmdfdGJsIHw+DQogIGRwbHlyOjptdXRhdGUoDQogICAgY2hvc2VuX3RlY2hub2xvZ3lfc3ViYXJlYSA9IGRwbHlyOjpjYXNlX3doZW4oDQogICAgICBzdHJpbmdyOjpzdHJfc3RhcnRzKHRpZHlyOjpyZXBsYWNlX25hKGNob3Nlbl9mb2N1c19hcmVhLCAiIiksICJUZWNobm9sb2d5ID4gIikgfg0KICAgICAgICBzdHJpbmdyOjpzdHJfcmVtb3ZlKGNob3Nlbl9mb2N1c19hcmVhLCAiXlRlY2hub2xvZ3kgPiAiKSwNCiAgICAgIFRSVUUgfiAiTm9uLVRlY2hub2xvZ3kiDQogICAgKQ0KICApDQoNCnRlY2hfY291bnRzX3JhdyA9IG1hcHBpbmdfdGJsX3dpdGhfdGVjaCB8PiANCiAgZHBseXI6OmNvdW50KGNob3Nlbl90ZWNobm9sb2d5X3N1YmFyZWEsIG5hbWUgPSAibiIpDQoNCnRlY2hfY291bnRzID0gdGliYmxlOjp0aWJibGUoc3ViYXJlYSA9IHRlY2hfbGV2ZWxzKSB8Pg0KICBkcGx5cjo6bGVmdF9qb2luKA0KICAgIHRlY2hfY291bnRzX3JhdyB8PiBkcGx5cjo6cmVuYW1lKHN1YmFyZWEgPSBjaG9zZW5fdGVjaG5vbG9neV9zdWJhcmVhKSwNCiAgICBieSA9ICJzdWJhcmVhIg0KICApIHw+DQogIGRwbHlyOjptdXRhdGUoDQogICAgbiA9IHRpZHlyOjpyZXBsYWNlX25hKG4sIDBMKSwNCiAgICBzdWJhcmVhID0gZm9yY2F0czo6ZmN0X3JlbGV2ZWwoc3ViYXJlYSwgIkFkdmFuY2VkIE1hbnVmYWN0dXJpbmciLCBhZnRlciA9IDApLA0KICAgIGNvbCA9IGRwbHlyOjppZl9lbHNlKHN1YmFyZWEgPT0gIkFkdmFuY2VkIE1hbnVmYWN0dXJpbmciLCBtaWFtaXJlZCwgIiNiMGIwYjAiKQ0KICApIHw+DQogIGRwbHlyOjphcnJhbmdlKHN1YmFyZWEpDQoNCnAyID0gZ2dwbG90Mjo6Z2dwbG90KHRlY2hfY291bnRzLCBnZ3Bsb3QyOjphZXMoeSA9IHN1YmFyZWEsIHggPSBuKSkgKw0KICBnZ3Bsb3QyOjpnZW9tX3NlZ21lbnQoZ2dwbG90Mjo6YWVzKHllbmQgPSBzdWJhcmVhLCB4ID0gMCwgeGVuZCA9IG4pLCBjb2xvciA9ICIjYjBiMGIwIikgKw0KICBnZ3Bsb3QyOjpnZW9tX3BvaW50KGdncGxvdDI6OmFlcyhjb2xvciA9IGNvbCksIHNpemUgPSAzLjIpICsNCiAgZ2dwbG90Mjo6c2NhbGVfY29sb3JfaWRlbnRpdHkoKSArDQogIGdncGxvdDI6Omdlb21fdGV4dChnZ3Bsb3QyOjphZXMobGFiZWwgPSBuKSwgaGp1c3QgPSAtMC40LCBzaXplID0gMy40KSArDQogIGdncGxvdDI6OmxhYnMoDQogICAgdGl0bGUgPSAiVGVjaG5vbG9neSBzdWJhcmVhcyByZXByZXNlbnRlZCBieSB0aGUgZGF0YXNldHMiLA0KICAgIHN1YnRpdGxlID0gIkFsbCBOU0YgdGVjaG5vbG9neSBzdWJhcmVhcyBzaG93biB0byByZXZlYWwgZ2FwczsgPGIgc3R5bGU9J2NvbG9yOiNjMzE0MmQ7Jz5BZHZhbmNlZCBNYW51ZmFjdHVyaW5nPC9iPiBoaWdobGlnaHRlZCIsDQogICAgeCA9ICJOdW1iZXIgb2YgZGF0YXNldHMiLCB5ID0gTlVMTCwNCiAgICBjYXB0aW9uID0gIlNvdXJjZTogbnNmLmdvdi9mb2N1cy1hcmVhcyAoc2NyYXBlZCk7IE1VIE5TRiBJRFNTIFRlYW0iDQogICkgKw0KICBnZ3Bsb3QyOjpjb29yZF9jYXJ0ZXNpYW4oeGxpbSA9IGMoMCwgbWF4KHRlY2hfY291bnRzJG4pICogMS4zICsgMC41KSkNCg0KIyBPcHRpb25hbDogZXhwbGljaXQgZ2FwIGNhbGxvdXQgaWYgemVybw0KYW1fbiA9IHRlY2hfY291bnRzJG5bdGVjaF9jb3VudHMkc3ViYXJlYSA9PSAiQWR2YW5jZWQgTWFudWZhY3R1cmluZyJdDQppZiAobGVuZ3RoKGFtX24pID09IDEgJiYgYW1fbiA9PSAwKSB7DQogIHAyID0gcDIgKw0KICAgIGdncGxvdDI6OmFubm90YXRlKCJsYWJlbCIsDQogICAgICB4ID0gbWF4KHRlY2hfY291bnRzJG4pICogMC42LCB5ID0gd2hpY2gobGV2ZWxzKHRlY2hfY291bnRzJHN1YmFyZWEpID09ICJBZHZhbmNlZCBNYW51ZmFjdHVyaW5nIiksDQogICAgICBsYWJlbCA9ICJHYXA6IE5vIGRhdGFzZXRzIG1hcHBlZCB0byBBZHZhbmNlZCBNYW51ZmFjdHVyaW5nIiwNCiAgICAgIGNvbG9yID0gIndoaXRlIiwgZmlsbCA9IG1pYW1pcmVkLCBsYWJlbC5zaXplID0gTkEsIHNpemUgPSAzLjUNCiAgICApDQp9DQpnZ3Bsb3QyOjpnZ3NhdmUoIi4uL2ZpZ3MvZmlnMDJfdGVjaG5vbG9neV9zdWJhcmVhc19nYXAucG5nIiwgcDIsIHdpZHRoID0gMTIsIGhlaWdodCA9IDUsIGRwaSA9IDMwMCkNCg0KIyBQbG90IDM6IEZsb3cgKGFsbHV2aWFsKSBmcm9tIERvbWFpbiAtPiBGb2N1cyAtPiBTdWJhcmVhDQpmbG93X2RmID0gbWFwcGluZ190Ymxfd2l0aF90ZWNoIHw+DQogIGRwbHlyOjptdXRhdGUoDQogICAgc3ViMyA9IGRwbHlyOjppZl9lbHNlKA0KICAgICAgaXMubmEoY2hvc2VuX3RlY2hub2xvZ3lfc3ViYXJlYSkgfCBjaG9zZW5fdGVjaG5vbG9neV9zdWJhcmVhID09ICIiLA0KICAgICAgIk5vbi1UZWNobm9sb2d5IiwNCiAgICAgIGNob3Nlbl90ZWNobm9sb2d5X3N1YmFyZWENCiAgICApDQogICkgfD4NCiAgZHBseXI6OmNvdW50KGRvbWFpbl9kaXNjaXBsaW5lLCBjaG9zZW5fZm9jdXNfYXJlYSwgc3ViMywgbmFtZSA9ICJuIikgfD4NCiAgZHBseXI6Om11dGF0ZSgNCiAgICBmaWxsX2dycCA9IGRwbHlyOjppZl9lbHNlKHN1YjMgPT0gIkFkdmNhbmNlZCBNYW51ZmFjdHVyaW5nIiwgImFtIiwgIm90aGVyIikNCiAgKQ0KDQpwMyA9IGdncGxvdDI6OmdncGxvdCgNCiAgZmxvd19kZiwNCiAgZ2dwbG90Mjo6YWVzKGF4aXMxID0gZG9tYWluX2Rpc2NpcGxpbmUsIGF4aXMyID0gY2hvc2VuX2ZvY3VzX2FyZWEsIGF4aXMzID0gc3ViMywgeSA9IG4pDQopICsNCiAgZ2dhbGx1dmlhbDo6Z2VvbV9hbGx1dml1bShnZ3Bsb3QyOjphZXMoZmlsbCA9IGZpbGxfZ3JwKSwgd2lkdGggPSAwLjIsIGFscGhhID0gMC43KSArDQogIGdnYWxsdXZpYWw6Omdlb21fc3RyYXR1bSh3aWR0aCA9IDAuMjUsIGZpbGwgPSAiI2IwYjBiMCIsIGNvbG9yID0gIndoaXRlIikgKw0KICBnZ3Bsb3QyOjpnZW9tX3RleHQoDQogICAgICAgIGdncGxvdDI6OmFlcygNCiAgICAgIGxhYmVsID0gZ2dwbG90Mjo6YWZ0ZXJfc3RhdChzdHJhdHVtKQ0KICAgICAgKSwNCiAgICBzdGF0ID0gZ2dhbGx1dmlhbDo6U3RhdFN0cmF0dW0sIA0KICAgIHNpemUgPSAyLjU1LCANCiAgICBmb250ZmFjZSA9ICJib2xkIiwNCiAgICBjb2xvciA9ICdibGFjaycNCiAgKSArDQogIGdncGxvdDI6OnNjYWxlX2ZpbGxfbWFudWFsKA0KICAgIHZhbHVlcyA9IGMoYW0gPSBtaWFtaXJlZCwgb3RoZXIgPSAnbGlnaHRncmF5JyksDQogICAgZ3VpZGUgPSAibm9uZSINCiAgKSArDQogIGdncGxvdDI6OmxhYnMoDQogICAgdGl0bGUgPSAiSG93IGRvbWFpbnMgbWFwIHRvIE5TRiBmb2N1cyBhcmVhcyBhbmQgdGVjaG5vbG9neSBzdWJhcmVhcyIsDQogICAgc3VidGl0bGUgPSAiV2lkdGhzIGluZGljYXRlIGRhdGFzZXQgY291bnRzOyA8YiBzdHlsZT0nY29sb3I6I2MzMTQyZDsnPkFkdmFuY2VkIE1hbnVmYWN0dXJpbmc8L2I+IGhpZ2hsaWdodGVkIHdoZW4gcHJlc2VudCIsDQogICAgeCA9IE5VTEwsIHkgPSAiRGF0YXNldHMiLA0KICAgIGNhcHRpb24gPSAiU291cmNlOiBuc2YuZ292L2ZvY3VzLWFyZWFzIChzY3JhcGVkKTsgTVUgTlNGIElEU1MgVGVhbSINCiAgKSArDQogIGdncGxvdDI6OnRoZW1lKA0KICAgIGF4aXMudGlja3MueCA9IGdncGxvdDI6OmVsZW1lbnRfYmxhbmsoKSwNCiAgICBheGlzLnRleHQueCAgPSBnZ3Bsb3QyOjplbGVtZW50X2JsYW5rKCksDQogICAgYXhpcy50aWNrcy55ID0gZ2dwbG90Mjo6ZWxlbWVudF9ibGFuaygpLA0KICAgIGF4aXMudGV4dC55ICA9IGdncGxvdDI6OmVsZW1lbnRfYmxhbmsoKQ0KICApDQoNCmdncGxvdDI6Omdnc2F2ZSgiLi4vZmlncy9maWcwM19kb21haW5fdG9fZm9jdXNfZmxvdy5wbmciLCBwMywgd2lkdGggPSAxMiwgaGVpZ2h0ID0gNSwgZHBpID0gMzAwKQ0KDQojIEFuaW1hdGlvbiBvZiB0aGUgdGhyZWUgcGxvdHMNCmltYWdlX2ZpbGVzID0gbGlzdC5maWxlcygiLi4vZmlncy8iLCBwYXR0ZXJuID0gIl5maWcwLipcXC5wbmckIiwgZnVsbC5uYW1lcyA9IFRSVUUpDQppbWFnZV9saXN0ID0gbWFnaWNrOjppbWFnZV9yZWFkKGltYWdlX2ZpbGVzKQ0KYW5pbWF0aW9uID0gbWFnaWNrOjppbWFnZV9hbmltYXRlKGltYWdlX2xpc3QsIGRlbGF5ID0gNzUwLCBsb29wID0gMCkNCg0KbWFnaWNrOjppbWFnZV93cml0ZShhbmltYXRpb24sICIuLi9maWdzL25zZl9pZHNzX2ZvY3VzX2FyZWFzX2FuaW1hdGlvbi5naWYiKQ0KDQphbmltYXRpb24NCmBgYA==